﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Text;
using System.Threading.Tasks;
using Abp;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.AutoMapper;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Extensions;
using Abp.Linq.Extensions;
using KDS.Mes.Mes.Storages.Dtos;
using KDS.Mes.Authorization;
using KDS.Mes.Dto;
using Abp.UI;
using KDS.Mes.Mes.AlcCodes;
using KDS.Mes.Mes.StorageAlcCodes;
using System.Collections.ObjectModel;

namespace KDS.Mes.Mes.Storages
{
    /// <summary>
    /// 仓库信息服务实现
    /// </summary>
    [AbpAuthorize(AppPermissions.Pages_Basic_Storages)]
    public class StorageAppService : MesAppServiceBase, IStorageAppService
    {
        private readonly IRepository<Storage, int> _storageRepository;
        private readonly IStorageListExcelExporter _storageListExcelExporter;
        private readonly IRepository<AlcCode, int> _alcCodeRepository;
        private readonly IRepository<StorageAlcCode, int> _storageAlcCodeRepository;

        private readonly StorageManage _storageManage;
        /// <summary>
        /// 构造方法
        /// </summary>
        public StorageAppService(
            IRepository<Storage, int> storageRepository,
            StorageManage storageManage, 
            IStorageListExcelExporter storageListExcelExporter,
            IRepository<AlcCode, int> alcCodeRepository,
            IRepository<StorageAlcCode, int> storageAlcCodeRepository
            )
        {
            _storageRepository = storageRepository;
            _storageManage = storageManage;
            _storageListExcelExporter = storageListExcelExporter;
            _alcCodeRepository = alcCodeRepository;
            _storageAlcCodeRepository = storageAlcCodeRepository;
        }

        #region 仓库信息管理
        public async Task<ListResultDto<StorageListDto>> GetStorages(GetStorageInput input)
        {
            var storages = await _storageRepository.GetAll()
                .ToListAsync();

            return new ListResultDto<StorageListDto>(storages.MapTo<List<StorageListDto>>());
        }
        public PagedResultDto<StorageListDto> GetPagedStorages(GetStorageInput input)
        {
            //初步过滤
            var query = _storageRepository.GetAll();
            //排序
            query = !string.IsNullOrEmpty(input.Sorting) ? query.OrderBy(x => x.Id) : query.OrderByDescending(t => t.CreationTime);
            //获取总数
            var tasksCount = query.Count();
            //默认的分页方式
            //var taskList = query.Skip(input.SkipCount).Take(input.MaxResultCount).ToList();
            //ABP提供了扩展方法PageBy分页方式
            var taskList = query.PageBy(input).ToList();
            return new PagedResultDto<StorageListDto>(tasksCount, taskList.MapTo<List<StorageListDto>>());
        }

        /// <summary>
        /// 根据查询条件获取仓库信息分页列表
        /// </summary>
        public async Task<PagedResultDto<StorageListDto>> GetPagedStoragesAsync(GetStorageInput input)
        {

            var query = _storageRepository.GetAll();
            //TODO:根据传入的参数添加过滤条件

            var storageCount = await query.CountAsync();

            var storages = await query
            .OrderBy(input.Sorting)
            .PageBy(input)
            .ToListAsync();

            var storageListDtos = storages.MapTo<List<StorageListDto>>();
            return new PagedResultDto<StorageListDto>(
            storageCount,
            storageListDtos
            );
        }

        /// <summary>
        /// 通过Id获取仓库信息信息进行编辑或修改 
        /// </summary>
        public async Task<GetStorageForEditOutput> GetStorageForEditAsync(NullableIdDto<int> input)
        {

            //获取所有的ALCCode
            var storageAlcCodeDtos = (await _alcCodeRepository.GetAll()
                .OrderBy(r => r.ALCCode)
                .Select(r => new StorageAlcCodeDto
                {
                    AlcCodeId = r.Id,
                    AlcCode = r.ALCCode
                })
                .ToArrayAsync());

            var output = new GetStorageForEditOutput
            {
                AlcCodes = storageAlcCodeDtos
            };


            //var output = new GetStorageForEditOutput();

            //StorageEditDto storageEditDto;

            //if (input.Id.HasValue)
            //{
            //    var entity = await _storageRepository.GetAsync(input.Id.Value);
            //    storageEditDto = entity.MapTo<StorageEditDto>();
            //}
            //else
            //{
            //    storageEditDto = new StorageEditDto();
            //}

            //output.Storage = storageEditDto;
            //return output;

            StorageEditDto storageEditDto;
            if (input.Id.HasValue)
            {
                var entity = await _storageRepository.GetAsync(input.Id.Value);
                storageEditDto = entity.MapTo<StorageEditDto>();
                output.Storage = storageEditDto;

                //针对每个ALCCode返回True/False 用于view页面判断是否选定
                foreach (var storageAlcCodeDto in storageAlcCodeDtos)
                {
                    storageAlcCodeDto.IsAssigned = await IsInAlcCodeAsync(entity, storageAlcCodeDto.AlcCode);
                }


                //var query = (from ln in _lineRepository.GetAll()
                //             join ws in _workshopRepository.GetAll() on ln.WorkshopId equals ws.Id
                //             where (ws.Id == output.Line.WorkshopId)
                //             select new
                //             {
                //                 wsFaId = ws.FactoryId,
                //             }).ToList();
                //output.Factorys = _factoryRepository.GetAllList()
                //   .Select(c => new ComboboxItemDto(c.Id.ToString(), c.FactoryName) { IsSelected = query.FirstOrDefault().wsFaId == c.Id })
                //   .ToList();

                //output.Workshops = _workshopRepository.GetAllList()
                //    .Where(c => c.FactoryId == query.FirstOrDefault().wsFaId)
                //    .Select(c => new ComboboxItemDto(c.Id.ToString(), c.WorkshopName) { IsSelected = output.Line.WorkshopId == c.Id })
                //    .ToList();

                //output.ProductModes = _productModeRepository.GetAllList()
                // .Select(c => new ComboboxItemDto(c.Id.ToString(), c.ProductModeName) { IsSelected = output.Line.ProductModeId == c.Id })
                // .ToList();
            }
            else
            {
                storageEditDto = new StorageEditDto();
                output.Storage = storageEditDto;
               // output.Factorys = _factoryRepository.GetAllList()
               //.Select(c => new ComboboxItemDto(c.Id.ToString(), c.FactoryName))
               //.ToList();

               // output.Workshops = _workshopRepository.GetAllList()
               //.Where(c => c.FactoryId == int.Parse(output.Factorys.FirstOrDefault().Value))
               //.Select(c => new ComboboxItemDto(c.Id.ToString(), c.WorkshopName))
               //.ToList();

                //output.ProductModes = _productModeRepository.GetAllList()
                //.Select(c => new ComboboxItemDto(c.Id.ToString(), c.ProductModeName))
                //.ToList();

            }
            //output.ProductModes = _productModeRepository.GetAllList()
            // .Select(c => new ComboboxItemDto(c.Id.ToString(), c.ProductModeName) { IsSelected = output.Line.ProductModeId == c.Id })
            // .ToList();
            return output;
        }


        /// <summary>
        /// 通过指定id获取仓库信息ListDto信息
        /// </summary>
        public async Task<StorageListDto> GetStorageByIdAsync(EntityDto<int> input)
        {
            var entity = await _storageRepository.GetAsync(input.Id);

            return entity.MapTo<StorageListDto>();
        }







        /// <summary>
        /// 新增或更改仓库信息
        /// </summary>
        public async Task CreateOrUpdateStorageAsync(CreateOrUpdateStorageInput input)
        {
            if (input.StorageEditDto.Id.HasValue)
            {
                await UpdateStorageAsync(input);
            }
            else
            {
                await CreateStorageAsync(input);
            }
        }

        /// <summary>
        /// 新增仓库信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Basic_Storages_Create)]
        public virtual async Task<StorageEditDto> CreateStorageAsync(CreateOrUpdateStorageInput input)
        {
            ////TODO:新增前的逻辑判断，是否允许新增
            //await CheckStorageIfAlreadyExists(input);
            //var entity = input.MapTo<Storage>();

            //entity = await _storageRepository.InsertAsync(entity);
            //return entity.MapTo<StorageEditDto>();

            //TODO:新增前的逻辑判断，是否允许新增
            //await CheckLineIfAlreadyExists(input);
            var entity = input.StorageEditDto.MapTo<Storage>();

            entity = await _storageRepository.InsertAsync(entity);

            //Assign alcCodes
            entity.AlcCodes = new Collection<StorageAlcCode>();
            foreach (var alcCodeName in input.AssignedAlcCodeNames)
            {
                var alcCode = await GetAlcCodeByNameAsync(alcCodeName);
                entity.AlcCodes.Add(new StorageAlcCode(entity.Id, alcCode.Id));
            }

            return entity.MapTo<StorageEditDto>();
        }

        /// <summary>
        /// 编辑仓库信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Basic_Storages_Edit)]
        public virtual async Task UpdateStorageAsync(CreateOrUpdateStorageInput input)
        {
            ////TODO:更新前的逻辑判断，是否允许更新
            //await CheckStorageIfAlreadyExists(input);
            //var entity = await _storageRepository.GetAsync(input.Id.Value);
            //input.MapTo(entity);

            //await _storageRepository.UpdateAsync(entity);


            //TODO:更新前的逻辑判断，是否允许更新
            //await CheckLineIfAlreadyExists(input);
            var entity = await _storageRepository.GetAsync(input.StorageEditDto.Id.Value);
            input.StorageEditDto.MapTo(entity);

            await SetAlcCodes(entity, input.AssignedAlcCodeNames);

            await _storageRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 删除仓库信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Basic_Storages_Delete)]
        public async Task DeleteStorageAsync(EntityDto<int> input)
        {
            //TODO:删除前的逻辑判断，是否允许删除
            await _storageRepository.DeleteAsync(input.Id);
        }

        /// <summary>
        /// 批量删除仓库信息
        /// </summary>
        [AbpAuthorize(AppPermissions.Pages_Basic_Storages_Delete)]
        public async Task BatchDeleteStorageAsync(List<int> input)
        {
            //TODO:批量删除前的逻辑判断，是否允许删除
            await _storageRepository.DeleteAsync(s => input.Contains(s.Id));
        }

        private async Task CheckStorageIfAlreadyExists(StorageEditDto input)
        {
            var existingStorage = await _storageRepository.GetAll()
                .FirstOrDefaultAsync(l => l.StorageName == input.StorageName || l.StorageCode == input.StorageCode);
            if (existingStorage == null)
            {
                return;
            }
            if (input.Id != null && existingStorage.Id == input.Id)
            {
                return;
            }
            throw new UserFriendlyException(L("ThisStorageAlreadyExists"));
        }

        /// <summary>
        /// 添加/移除AlcCode
        /// </summary>
        /// <param name="line"></param>
        /// <param name="alcCodeNames"></param>
        /// <returns></returns>
        public virtual async Task<bool> SetAlcCodes(Storage storage, string[] alcCodeNames)
        {
            //Remove from removed alcCodes
            foreach (var storageAlcCode in storage.AlcCodes.ToList())
            {
                var alcCode = await _alcCodeRepository.FirstOrDefaultAsync(storageAlcCode.AlcCodeId);

                if (alcCode != null && alcCodeNames.All(alcCodeName => alcCode.ALCCode != alcCodeName))
                {
                    await RemoveFromAlcCodeAsync(storage, alcCode.ALCCode);
                }
            }

            //Add to added alcCodes
            foreach (var alcCodeName in alcCodeNames)
            {
                var alcCode = await GetAlcCodeByNameAsync(alcCodeName);
                if (storage.AlcCodes.All(ur => ur.AlcCodeId != alcCode.Id))
                {
                    await AddToAlcCodeAsync(storage, alcCodeName);
                }
            }

            return true;
        }

        public virtual async Task RemoveFromAlcCodeAsync(Storage user, string roleName)
        {
            var role = await GetAlcCodeByNameAsync(roleName);
            var userRole = await _storageAlcCodeRepository.FirstOrDefaultAsync(ur => ur.StorageId == user.Id && ur.AlcCodeId == role.Id);
            if (userRole == null)
            {
                return;
            }

            await _storageAlcCodeRepository.DeleteAsync(userRole);
        }
        private async Task<AlcCode> GetAlcCodeByNameAsync(string alcCodeName)
        {
            var alcCode = await _alcCodeRepository.FirstOrDefaultAsync(r => r.ALCCode == alcCodeName);
            if (alcCode == null)
            {
                throw new AbpException("Could not find a role with name: " + alcCodeName);
            }
            return alcCode;
        }
        public virtual async Task AddToAlcCodeAsync(Storage storage, string alcCodeName)
        {
            var alcCode = await GetAlcCodeByNameAsync(alcCodeName);
            await _storageAlcCodeRepository.InsertAsync(new StorageAlcCode(storage.Id, alcCode.Id));
        }

        public virtual async Task<bool> IsInAlcCodeAsync(Storage storage, string alcCodeName)
        {
            var role = await GetAlcCodeByNameAsync(alcCodeName);
            return await _storageAlcCodeRepository.FirstOrDefaultAsync(ur => ur.StorageId == storage.Id && ur.AlcCodeId == role.Id) != null;
        }

        #endregion


        #region 仓库信息的Excel导出功能


        public async Task<FileDto> GetStorageToExcel()
        {
            var entities = await _storageRepository.GetAll().ToListAsync();

            var dtos = entities.MapTo<List<StorageListDto>>();

            var fileDto = _storageListExcelExporter.ExportStorageToFile(dtos);



            return fileDto;
        }


        #endregion










    }
}
